/* $Id: tabbed.jquery.js 29 2009-10-22 19:58:19Z geraldb $

Unobtrusive jQuery Tooltips

Author:
	gburns

TODO:
	documentation

*/

(function($) {
$.pluggie('tooltip', function() {
	var defaultSettings = {
		prefix: 'tooltip_',
		showAt: 'this',
		horizontalAlignment: 'right',
		horizontalOffset: 0,
		verticalAlignment: 'top',
		verticalOffset: 0,
		appendTo: 'body',
		tooltipSelector: '.tooltip',
		constrainTo: 'viewport',
		trigger_show: 'mouseover',
		trigger_hide: 'mouseout'
	};

	var vertical_alignment_options = {top: 'top', bottom: 'bottom', middle: 'middle'};
	var horizontal_alignment_options = {right: 'right', left: 'left', center: 'center'};

	var settings = null;
	var $object = null;
	var $all_objects = null;
	var prefix;
	var me = this;

	var show_at;
	var vertical_alignment;
	var vertical_offset;
	var horizontal_alignment;
	var horizontal_offset;
	var append_to;
	var tooltip_selector;
	var constrain_to;
	var trigger_show;
	var trigger_hide;

	this._init = function(object, parameters, orig_object) {
		$object = object;
		$all_objects = orig_object;
		settings = $.extend(defaultSettings, parameters || {});

		prefix = settings.prefix;

		show_at = settings.showAt;
		if ( (typeof show_at == 'object' && !show_at.jquery) || (typeof show_at == 'string' && show_at != 'this') ) {
			show_at = $(show_at)
		} else {
			show_at = $object;
		}

		vertical_alignment = vertical_alignment_options[settings.verticalAlignment] || 'top';
		vertical_offset = parseInt(settings.verticalOffset) || 0;
		horizontal_alignment = horizontal_alignment_options[settings.horizontalAlignment] || 'right';
		horizontal_offset = parseInt(settings.horizontalOffset) || 0;
		append_to = settings.appendTo;
		tooltip_selector = settings.tooltipSelector;
		constrain_to = settings.constrainTo;
		if ( constrain_to != 'viewport' && (constrain_to = $(constrain_to)) && !constrain_to.length ) constrain_to = $('body');
		trigger_show = settings.trigger_show;
		trigger_hide = settings.trigger_hide;

		$(tooltip_selector, $all_objects).hide();

		$object
			.bind(trigger_show, me.show_tooltip);

		$object
			.bind(trigger_hide, me.delay_hide_tooltip);
	}

	var hide_timeout;
	this.show_tooltip = function() {
		clearTimeout(hide_timeout);
		$(tooltip_selector, $all_objects.not($object[0])).hide();

		if ( !$(tooltip_selector, $object).is(':visible') ) {
			$(tooltip_selector, $object).show();
			me.position_tooltip();
		}
	};

	
	this.delay_hide_tooltip = function() {
		hide_timeout = setTimeout(me.hide_tooltip, 500);
	};

	this.hide_tooltip = function() {
		$(tooltip_selector, $object).hide();
	};

	this.position_tooltip = function() {
		var $tooltip = $(tooltip_selector, $object);
		var attr = constrain_attributes();
		$tooltip
			.css({
				position: 'absolute',
				left: 0,
				top: 0
			});

		var left_offset = show_at.offset().left - $tooltip.offset().left;
		var top_offset = show_at.offset().top - $tooltip.offset().top;

		var top;
		if ( vertical_alignment == 'top' ) {
			top = top_offset - $tooltip.outerHeight() + vertical_offset;
		} else if ( vertical_alignment == 'bottom' ) {
			top = top_offset - show_at.offset().bottom + vertical_offset;
		} else if ( vertical_alignment == 'middle' ) {
			top = top_offset - show_at.offset().top + (show_at.outerHeight() / 2) - ($tooltip.outerHeight() / 2) + vertical_offset;
		}

		var left;
		if ( horizontal_alignment == 'left' ) {
			left = left_offset - $tooltip.outerWidth() + horizontal_offset;
		} else if ( horizontal_alignment == 'right' ) {
			left = left_offset + show_at.outerWidth() + horizontal_offset;
		} else if ( horizontal_alignment == 'center' ) {
			left = left_offset - show_at.offset().left + (show_at.outerWidth() / 2) - ($tooltip.outerWidth() / 2) + horizontal_offset;
		}

		$tooltip
			.css({
				left: left,
				top: top
			});

		if ( $tooltip.offset().left < attr.left ) {
			$tooltip
				.css({
					left: left + (attr.left - $tooltip.offset().left)
				});
		} else if ( $tooltip.offset().left + $tooltip.outerWidth(true) > attr.left + attr.width ) {
			$tooltip
				.css({
					left: left - (($tooltip.offset().left + $tooltip.outerWidth(true)) - (attr.left + attr.width))
				});
		}

		if ( $tooltip.offset().top < attr.top ) {
			$tooltip
				.css({
					top: top + (attr.top - $tooltip.offset().top)
				});
		} else if ( $tooltip.offset().top + $tooltip.outerHeight(true) > attr.top + attr.height ) {
			$tooltip
				.css({
					top: top - (($tooltip.offset().top + $tooltip.outerHeight(true)) - (attr.top + attr.height))
				});
		}
	}

	var constrain_attributes = function() {
		var left;
		var top;
		var width;
		var height;

		if ( constrain_to == 'viewport' ) {
			left = $.viewport.left();
			top = $.viewport.top();
			width = $.viewport.width();
			height = $.viewport.height();
		} else {
			left = constrain_to.offset().left;
			top = constrain_to.offset().left;
			width = constrain_to.outerWidth();
			height = constrain_to.outerHeight();;
		}

		return {left: left, top: top, width: width, height: height};
	}
});
})(jQuery);
